<?php

require_once 'ElementValidationException.php';

class ElementValidation {
	
	/**
	 * Standard validation rules
	 */
	const REGEX_USERNAME = '/^[a-z0-9\-\.]{4,}$/i';
	const REGEX_EMAIL = '/^[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*+[a-z]{2}/is';
	const REGEX_PHONE_NUMBER = '#^(((00|\+)(\d{1,3}|(1\-\d{3}))|0)[ -]?((\d{2}[ -]?\d{7})|(\d{3}[ -]?\d{6})|(6[ -]?\d{8})))$#';
	const REGEX_NUMBER = '/^[1-9]([0-9]+)?$/';
	
	/**
	 * The elements this element must be equal to.
	 *
	 * @var FormElement[]
	 */
	private $compareEquals = array ();
	
	/**
	 * The regular expression which this element must match against.
	 *
	 * @var string
	 */
	private $compareMatch = array ();
	
	private $validateAgainst = null;
	
	/**
	 * Whether or not the element is required.
	 *
	 * @var boolean
	 */
	private $isRequired = array (false, '' );
	
	private $methods = array();
	
	function __construct( FormElement $fe ) {
		$this->validateAgainst = $fe;
	}
	
	/**
	 * Makes the element required.
	 *
	 * @param String $errorMessage
	 */
	public function required( $errorMessage ) {
		$this->isRequired = array (true, $errorMessage );
	}
	
	/**
	 * Adds a field to which this field must be equal.
	 *
	 * @param FormElement $formElement
	 */
	public function compareEquals( FormElement $formElement, $errorMessage ) {
		$this->compareEquals [ ] = array ($formElement, $errorMessage );
	}
	
	/**
	 * Sets the regex this element must match to.
	 *
	 * @param String $regex
	 */
	public function compareMatch( $regex, $errorMessage ) {
		$this->compareMatch[] = array ($regex, $errorMessage );
	}
	
	/**
	 * Validates the form element using the specified rules.
	 *
	 * @param FormElement $validateAgainst
	 */
	public function validate( ) {
		if ( $this->isRequired [ 0 ] ) {
			if( method_exists( $this->validateAgainst, 'isEmpty' ) ) {
				 if( $this->validateAgainst->isEmpty() ) {
				 	throw new ElementValidationException( $this->isRequired [ 1 ] );
				 }
			} else {
				if( $this->validateAgainst instanceof FormElement && $this->validateAgainst->getProperty( 'value' ) == '' ) {
					throw new ElementValidationException( $this->isRequired [ 1 ] );
				}
			}
		}
		
		$value = $this->validateAgainst->getProperty('value');
		if ( count( $this->compareMatch ) > 0 && $this->validateAgainst instanceof FormElement && ( $this->isRequired[0] || !empty( $value ) ) ) {
			foreach( $this->compareMatch as $compareElement ) {
				if ( !preg_match( $compareElement [ 0 ], $this->validateAgainst->getProperty( "value" ) ) ) {
					throw new ElementValidationException( $compareElement [ 1 ] );
				}
			}
		}

		// Invoke the validation methods.
		foreach( $this->methods as $method ) {
			if( !call_user_func( $method[0], $this->validateAgainst ) ) {
				throw new ElementValidationException( $method[ 1 ] );
			}
		}
		
		if ( count( $this->compareEquals ) > 0 ) {
			foreach ( $this->compareEquals as $compareElement ) {
				if ( !$compareElement [ 0 ]->compareTo( $this->validateAgainst ) ) {
					throw new ElementValidationException( $compareElement [ 1 ] );
				}
			}
		}
		
	}
	
	const REQUIRED = 1;
	const METHOD = 2;
	const REGEX_MATCH = 3;
	const EQUAL_TO = 4;
	
	public function removeRulesByType( $type = 0 ) {
		switch( $type ) {
			case self::REQUIRED:
				$this->isRequired[0] = false;
				break;
			
			case self::METHOD:
				$this->methods = array();
				break;
				
			case self::REGEX_MATCH:
				$this->compareMatch = array();
				break;
				
			case self::EQUAL_TO:
				$this->compareEquals = array();
				break;
		}
	}
	
	public function method( $method, $errorMessage ) {
		$this->methods[] = array( $method, $errorMessage );
	}
}

?>